package com.example.nowcodercommunity.util;

import org.apache.commons.lang3.CharUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

@Component
public class SensitiveFilter {

    private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);

    private static final String REPLACEMENT = "*";

    private Trie rootTrie = new Trie();

    @PostConstruct
    public void init() throws IOException {

        BufferedReader bufferedReader = null;
        InputStreamReader reader = null;
        InputStream is = null;

        try {
            is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
            reader = new InputStreamReader(is);
            bufferedReader = new BufferedReader(reader);

            String keyWord = null;
            while ((keyWord = bufferedReader.readLine()) != null) {
                this.rootTrie.add(keyWord);
            }

            bufferedReader.close();
            reader.close();
            is.close();
        } catch (IOException e) {
            logger.error("加载敏感词文件失败！");
        } finally {
            bufferedReader.close();
            reader.close();
            is.close();
        }
    }

    public String filter(String text){
        if(StringUtils.isEmpty(text)){
            return text;
        }
        StringBuilder sb = new StringBuilder();

        Trie triePoint = this.rootTrie;
        int start = 0;
        int end = 0;

        while (start<text.length()){
            if(end>=text.length()){
                end = start;
                triePoint = this.rootTrie;
            }
            char c = text.charAt(end);

            if(isSymbol(c)){
                if(start==end){
                    start++;
                    end++;
                }else{
                    end++;
                }
                continue;
            }

            if(triePoint.child.containsKey(c)){
                triePoint = triePoint.child.get(c);
                if(triePoint.isEnd){
                    sb.append(REPLACEMENT);
                    start = end+1;
                    end = start;
                    triePoint = this.rootTrie;
                }else{
                    end++;
                }
            }else{
                sb.append(text.charAt(start));
                start++;
                end = start;
                triePoint = this.rootTrie;
            }
        }

        return sb.toString();
    }

    private boolean isSymbol(char c){
        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }
    private class Trie{
        private char str;
        private Map<Character,Trie> child;
        private boolean isEnd;

        public Trie(){
            this.child = new HashMap<>();
            this.isEnd = false;
        }

        public Trie(char s){
            this.str = s;
            this.child = new HashMap<>();
            this.isEnd = false;
        }

        public boolean isEnd() {
            return isEnd;
        }

        public void setEnd(boolean end) {
            isEnd = end;
        }

        public void add(String word){
            Trie node = this;

            for(int i=0;i<word.length();i++){
                char s = word.charAt(i);
                if(node.child.containsKey(s)){
                    node = node.child.get(s);
                }else{
                    Trie trie = new Trie(s);
                    node.child.put(s,trie);
                    node = trie;
                }
            }

            node.setEnd(true);
        }
    }
}
